#include "precompiled/pchnscene.h"
//------------------------------------------------------------------------------
//  ngeometrynode_main.cc
//  (C) 2004 Conjurer Services, S.A.
//------------------------------------------------------------------------------
#include "nscene/ngeometrynode.h"
#include "nscene/nsurfacenode.h"
#include "nscene/nscenegraph.h"
#include "nscene/nsceneshader.h"
//#include "nscene/ncsceneclass.h"
#include "gfx2/nmesh2.h"
#include "gfx2/ngfxserver2.h"

nNebulaScriptClass(nGeometryNode, "nabstractshadernode");

uint nGeometryNode::uniqueGeometryId = 0;

//------------------------------------------------------------------------------
/**
*/
nGeometryNode::nGeometryNode() :
    worldCoord(false)
{
    this->geometryId = uniqueGeometryId++;
    this->streamId = this->geometryId;
}

//------------------------------------------------------------------------------
/**
*/
nGeometryNode::~nGeometryNode()
{
    this->UnloadResources();

    // unload surface resources
    if (this->refSurfaceNode.isvalid())
    {
        this->refSurfaceNode->Release();
    }
}

//------------------------------------------------------------------------------
/**
    Load the resources needed by this object.
*/
bool
nGeometryNode::LoadResources()
{
    kernelServer->PushCwd(this);
    bool success = true;

    success = nAbstractShaderNode::LoadResources();
    if (success)
    {
        if (this->refSurfaceNode.isvalid())
        {
            success = this->refSurfaceNode->LoadResources();
        }
    }

    kernelServer->PopCwd();

    return success;
}

//------------------------------------------------------------------------------
/**
    Unload the resources if refcount has reached zero.
*/
void
nGeometryNode::UnloadResources()
{
    nAbstractShaderNode::UnloadResources();

    if (this->refSurfaceNode.isvalid())
    {
        //FIXME ma.garcias- can't unload surface resources, they could be shared
        //this->refSurfaceNode->UnloadResources();
    }
}

//------------------------------------------------------------------------------
/**
*/
void
nGeometryNode::RenderContextCreated(nRenderContext* renderContext)
{
    //create a cache entry for the entity
    //if the node is used more than once in the entity (decals)
    //all instances will share the same index (which is fine)
    nSceneNode::RenderContextCreated(renderContext);
}

//------------------------------------------------------------------------------
/**
*/
void
nGeometryNode::RenderContextDestroyed(nRenderContext* renderContext)
{
    nSceneNode::RenderContextDestroyed(renderContext);
}

//------------------------------------------------------------------------------
/**
    Attach shape to the scene graph, once for every render pass,
    which comes defined by its surface.
*/
void
nGeometryNode::Attach(nSceneGraph* sceneGraph, nRenderContext* renderContext)
{
    n_assert(renderContext);

    nSceneNode::Attach(sceneGraph, renderContext);
}

//------------------------------------------------------------------------------
/**
    Perform pre-instancing geometry rendering.
*/
bool
nGeometryNode::Apply(nSceneGraph* sceneGraph)
{
    return nAbstractShaderNode::Apply(sceneGraph);
}

//------------------------------------------------------------------------------
/**
    Perform post-instancing geometry rendering.

    This is ensured to be called for any geometry node when the last
    instance of the node has been rendered, either because the shader or
    the surface is about to change, or because it was the last in the list.
    Override this method to perform specific post-instancing rendering, eg.
    end a streamed rendering operation, etc.
*/
bool
nGeometryNode::Flush(nSceneGraph* /*sceneGraph*/)
{
    return true;
}

//------------------------------------------------------------------------------
/**
    Common behavior for all geometry nodes.
    
    nXXXNode::Render(sceneGraph, renderContext)
    {
        if( nGeometryNode::Render(sceneGraph, renderContext) )
        {
            // ...
        }
        // ...
    }
*/
bool
nGeometryNode::Render(nSceneGraph* sceneGraph, nRenderContext* renderContext)
{
    // animate shader parameters
    this->InvokeAnimators(renderContext);
    
    // set per-shape shader parameters
    nAbstractShaderNode::Render(sceneGraph, renderContext);
    
    // set shader overrides
    // (this is called last to allow overriding per-shape parameters)
    nShader2 *shader = nSceneServer::Instance()->GetShaderAt(sceneGraph->GetShaderIndex()).GetShaderObject();
    shader->SetParams(renderContext->GetShaderOverrides());
    
    return true;
}
